﻿using AIStudio.Util.Primitives;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using System;
using System.Linq;
using System.Net.WebSockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace AIStudio.WeChat.Api.WebSocketEx
{
    public interface ICustomWebSocketMessageHandler
    {
        Task SendInitialMessages(CustomWebSocket userWebSocket, string anyText = "#OK");
        Task HandleMessage(WebSocketReceiveResult result, byte[] buffer, CustomWebSocket userWebSocket, ICustomWebSocketFactory wsFactory);
        Task BroadcastOthers(byte[] buffer, CustomWebSocket userWebSocket, ICustomWebSocketFactory wsFactory);
        Task BroadcastAll(byte[] buffer, ICustomWebSocketFactory wsFactory);
        Task BroadcastOthers(string userIds, CustomWebSocket userWebSocket, object message);
    }

    public class CustomWebSocketMessageHandler : ICustomWebSocketMessageHandler
    {
        private readonly ICustomWebSocketFactory _wsFactory;
        private readonly ILogger _logger;
        public CustomWebSocketMessageHandler(ICustomWebSocketFactory wsFactory, ILogger<CustomWebSocketMessageHandler> logger)
        {
            _wsFactory = wsFactory;
            _logger = logger;
        }

        public async Task SendInitialMessages(CustomWebSocket userWebSocket, string anyText = "#OK")
        {
            WebSocket webSocket = userWebSocket.WebSocket;
            MessageResult send = new MessageResult()
            {
                Success = true,
                Data = new D_UserMessageDTO
                {
                    CreateTime = DateTime.Now,
                    Text = anyText,
                    CreatorId = "system",
                    CreatorName = "system",
                },
                MessageType = WSMessageType.Success,
            };

            string serialisedMessage = JsonConvert.SerializeObject(send);
            byte[] bytes = Encoding.ASCII.GetBytes(serialisedMessage);
            await webSocket.SendAsync(new ArraySegment<byte>(bytes, 0, bytes.Length), WebSocketMessageType.Text, true, CancellationToken.None);

        }

        public async Task HandleMessage(WebSocketReceiveResult result, byte[] buffer, CustomWebSocket userWebSocket, ICustomWebSocketFactory wsFactory)
        {
            string msg = Encoding.UTF8.GetString(buffer.Reverse().SkipWhile(x => x == 0).Reverse().ToArray());
            try
            {
                var message = JsonConvert.DeserializeObject<MessageResult>(msg);

                if (message.MessageType == WSMessageType.MessageType)
                {
                    var data = JsonConvert.DeserializeObject<D_UserMessageDTO>((message.Data ?? "").ToString());
                    if (data == null)
                        return;

                    MessageResult send = new MessageResult()
                    {
                        Success = true,
                        Data = data,
                        MessageType = WSMessageType.MessageType,
                    };
                    byte[] bytes = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(send));
                    //数据回发一份，所有界面能同步，没有考虑该用户同时在同时多个地方登录。
                    await userWebSocket.WebSocket.SendAsync(new ArraySegment<byte>(bytes, 0, bytes.Length), WebSocketMessageType.Text, true, CancellationToken.None);

                    //转发给收信人
                    await BroadcastOthers(data, userWebSocket, wsFactory);


                }       
                else if (message.MessageType == WSMessageType.OnlineUser)//在线用户
                {
                    MessageResult send = new MessageResult()
                    {
                        Success = true,
                        Data = _wsFactory.All(),
                        MessageType = WSMessageType.OnlineUser,
                    };
                    byte[] bytes = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(send));
                    await userWebSocket.WebSocket.SendAsync(new ArraySegment<byte>(bytes, 0, bytes.Length), WebSocketMessageType.Text, true, CancellationToken.None);
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(UserLogType.WebSocket.ToEventId(), ex, ex.Message);
            }

        }

        public async Task BroadcastOthers(D_UserMessageDTO message, CustomWebSocket userWebSocket, ICustomWebSocketFactory wsFactory)
        {
            MessageResult send = new MessageResult()
            {
                Success = true,
                Data = message,
                MessageType = WSMessageType.MessageType,
            };

            await BroadcastOthers(message.UserIds, userWebSocket, send);
        }

        public async Task BroadcastOthers(string userIds, CustomWebSocket userWebSocket, object message)
        {
            string[] receives = userIds.Split(new string[] { "^" }, StringSplitOptions.RemoveEmptyEntries);
            byte[] bytes = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(message));

            foreach (var userId in receives.Distinct())
            {
                var others = _wsFactory.Client(userId);
                foreach (var other in others)
                {
                    if (other != userWebSocket)//不要发给自己
                    {
                        await other.WebSocket.SendAsync(new ArraySegment<byte>(bytes, 0, bytes.Length), WebSocketMessageType.Text, true, CancellationToken.None);
                    }
                }
            }
        }

        public async Task BroadcastOthers(byte[] buffer, CustomWebSocket userWebSocket, ICustomWebSocketFactory wsFactory)
        {
            var others = wsFactory.Others(userWebSocket);
            foreach (var other in others)
            {
                await other.WebSocket.SendAsync(new ArraySegment<byte>(buffer, 0, buffer.Length), WebSocketMessageType.Text, true, CancellationToken.None);
            }
        }

        public async Task BroadcastAll(byte[] buffer, ICustomWebSocketFactory wsFactory)
        {
            var all = wsFactory.All();
            foreach (var uws in all)
            {
                await uws.WebSocket.SendAsync(new ArraySegment<byte>(buffer, 0, buffer.Length), WebSocketMessageType.Text, true, CancellationToken.None);
            }
        }

   }
}
